package uk.ac.bath.domains.mover;


import java.util.Collection;
import java.util.Vector;

import java.util.logging.Level;
import java.util.logging.Logger;
import uk.ac.bath.domains.misc.Point2DInt;
import uk.ac.bath.base.Point;
import uk.ac.bath.base.Cell;
import uk.ac.bath.base.MachineIF;

import uk.ac.bath.util.MyRandom;
import uk.ac.bath.util.Tweakable;
import uk.ac.bath.util.TweakableDouble;
import uk.ac.bath.util.TweakableInt;

public class MoverCellMrkI extends MoverCell {

    public static Vector<Tweakable> tweaks = new Vector<Tweakable>();
    public static TweakableDouble cellMutateProb =
            new TweakableDouble(tweaks, 0.0, 1.0, 0.001, 0.0001, "MutateProb");
    public static TweakableInt tickCost =
            new TweakableInt(tweaks, 0, 200, 10, "TickCost");
    public static TweakableInt moveCost =
            new TweakableInt(tweaks, 0, 200, 10, "MoveCost");
    public static TweakableInt maxBite =
            new TweakableInt(tweaks, 0, 200, 30, "MaxBite");
    public static TweakableInt cloneThreshold =
            new TweakableInt(tweaks, 0, 4000, 120, "CloneThreshold");
    private MoverEnvironment env;

    public Collection<Tweakable> getTweaks() {
        return tweaks;
    }

    final public static int minOperatorsPerCell = 5;


    public MoverCellMrkI(MoverEnvironment env,MachineIF machine,
            Point point,
            double fitness,
            int id,
            int generation,
            int mutations,
            String tag) {
        super(machine, point, fitness, id, generation, mutations, tag);
        this.env=env;
    }

//    public MoverCellMrkI() {
//        super(null, null, 0, 0, -1, 0, "MoverMRKI Proto");
//    }

    public Cell cloneToPoint(Point p, double fitness) {
        try {
            return new MoverCellMrkI(env,(MachineIF) (machine.clone()), p, fitness, id_, generation + 1, mutationCount, tag);
        } catch (CloneNotSupportedException ex) {
            Logger.getLogger(MoverCellMrkI.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;

    }


    public void tickImpl() {

      //  MoverEnvironment env = (MoverEnvironment) env1;
        age++;
        if (fitness <= 0) {
            return;
        }

        if (fitness > cloneThreshold.getNumber().doubleValue()) {
            Point pNew = env.randomEmptyAdjacent(point);
            if (pNew != null) {
                double newFit = ((MoverCellFactoryIF)((MoverEnvironment)env).factory).getInitFitness();
                Cell newCell = cloneToPoint(pNew, newFit);
                fitness -= newFit;
                if (MyRandom.nextDouble() <
                        cellMutateProb.getNumber().doubleValue()) {
                    // newCell.mutate(pallete);
                    env.mutateCell(newCell);
                }
                env.addCell(newCell);
            }
        }

        int fVal;
        if (env.getFoodAt(point) > 0.0) {
            fVal = 1;
        } else {
            fVal = 0;
        }

        fitness += env.eatFoodAt(point, maxBite.getNumber().doubleValue());


        machine.setIn(0,fVal);
        machine.setIn(-1,fVal);
        machine.setIn(-2,fVal);


        machine.tick();



      //  VectorState state = machine.getState();


        Point2DInt newPoint = (Point2DInt) point.clone();

        int n = 0;

        if (machine.isOn(1)) {
            newPoint.x++;
            n++;
        }

        if (machine.isOn(2)) {
            newPoint.x--;
            n++;
        }

        if (machine.isOn(3)) {
            newPoint.y++;
            n++;
        }

        if (machine.isOn(4)) {
            newPoint.y--;
            n++;
        }


        fitness -= tickCost.getNumber().doubleValue() + n * moveCost.getNumber().doubleValue();

        if (!env.getSpace().contains(newPoint)) {
            fitness = -1;
            return;
        }


        Cell c = null;

        if (!newPoint.equals(point)) {
            c = env.cellAt(newPoint);
            if (c == null) {
                prevPoint.set(point);
                point.set(newPoint);
                env.moveCell(this);
                return;
            } else {
                //		collideWith(c);
            }
        }
    }
}




